﻿using System;
using System.Diagnostics;
using System.Net;
using System.ServiceModel.Description;
using System.Windows.Forms;
using System.Collections;
using System.Configuration;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Client;
using Microsoft.Xrm.Sdk.Messages;
using Microsoft.Xrm.Sdk.Query;
using SKYPE4COMLib;


namespace SkypeConnector
{
    public partial class trayForm : Form
    {
        public static Skype skype = new Skype();
        DateTime startTime;
        DateTime endTime;
        Guid contactGuidId;
        Guid accountID;
        Guid skypeId = Guid.Empty;
        private OrganizationServiceProxy _serviceProxy;
        private IOrganizationService _service;        
        bool callProcessed = false;
        string contactID;
        string firstName;
        string lastName;
        string email;
        string companyName;
        string jobTitle;
        UriBuilder organizationUri;
        string crmServer;
        int crmServerPort;
        string crmOrgName;
        string crmDomain;
        string crmUsername;
        string crmPassword;
        int useHTTPS;
        ArrayList skypeMessages;

        public trayForm()
        {
            InitializeComponent();

            try
            {
                // Attach Skype
                skype.Attach(9, false);

                // Create arraylist for messages
                skypeMessages = new ArrayList();

                // When the Skype call is received pass it to OurCallStatus() method
                ((_ISkypeEvents_Event)skype).CallStatus += OurCallStatus;
                // When the Skype message is received pass it to IncomingCall_MessageStatus() method
                ((_ISkypeEvents_Event)skype).MessageStatus += new _ISkypeEvents_MessageStatusEventHandler(IncomingCall_MessageStatus);

                //Get the application config data from app.config
                crmServer = ConfigurationManager.AppSettings["CRMServer"];
                useHTTPS = Int32.Parse(ConfigurationManager.AppSettings["useHTTPS"]);
                crmServerPort = Int32.Parse(ConfigurationManager.AppSettings["CRMServerPort"]);
                crmOrgName = ConfigurationManager.AppSettings["CRMOrgName"];
                crmDomain = ConfigurationManager.AppSettings["CRMDomain"];
                crmUsername = ConfigurationManager.AppSettings["CRMUsername"];
                crmPassword = ConfigurationManager.AppSettings["CRMPassword"];

                // Create a connection to CRM
                if (useHTTPS == 0)
                {
                    organizationUri = new UriBuilder("http", crmServer, crmServerPort, crmOrgName + "/XRMServices/2011/Organization.svc");
                }
                else if (useHTTPS == 1)
                {
                    organizationUri = new UriBuilder("https", crmServer, crmServerPort, crmOrgName + "/XRMServices/2011/Organization.svc");
                }

                Uri homeRealmUri = null;
                ClientCredentials credentials = new ClientCredentials();
                // set default credentials for OrganizationService
                credentials.Windows.ClientCredential = new NetworkCredential(crmUsername, crmPassword, crmDomain);

                //Create serviceProxy
                _serviceProxy = new OrganizationServiceProxy(organizationUri.Uri, homeRealmUri, credentials, null);

                _service = (IOrganizationService)_serviceProxy;              
           
            }
            catch (Exception ex)
            {
            }
        }


        public void OurCallStatus(Call call, TCallStatus status)
        {
            // Always use try/catch with ANY Skype calls.
            try
            {
                // If Skype is ringing
                if (call.Status == TCallStatus.clsRinging)
                {
                    if (callProcessed == false)
                    {
                        callProcessed = true;
                        startTime = DateTime.Now;
                        EntityCollection returnCollection = SearchBySkypeUsername(call.PartnerHandle);
                        // if we found a contact with skype username
                        if (returnCollection.Entities.Count > 0)
                        {
                            firstName = returnCollection.Entities[0].Attributes["firstname"].ToString();
                            lastName = returnCollection.Entities[0].Attributes["lastname"].ToString();
                            if (returnCollection.Entities[0].Attributes.Contains("emailaddress1") == true)
                                email = returnCollection.Entities[0].Attributes["emailaddress1"].ToString();
                            companyName = returnCollection.Entities[0].Attributes["name"].ToString();
                            if (returnCollection.Entities[0].Attributes.Contains("jobtitle") == true)
                                jobTitle = returnCollection.Entities[0].Attributes["jobtitle"].ToString();
                            if (returnCollection.Entities[0].Attributes.Contains("parentcustomerid") == true)
                                accountID = ((EntityReference)returnCollection.Entities[0].Attributes["parentcustomerid"]).Id;

                            contactID = returnCollection.Entities[0].Attributes["contactid"].ToString();
                            contactGuidId = (Guid)returnCollection.Entities[0].Attributes["contactid"];

                            MessageForm form = MessageForm.getInstance();
                            form.fadeIn();
                            form.FillData(firstName, lastName, email, companyName, jobTitle, contactGuidId, accountID);
                            callProcessed = true;
                        }
                        // no contact was found with that skype username
                        else
                        {
                            //try searching by skype display name
                            EntityCollection returnCollection2 = SearchByContactName(call.PartnerDisplayName);
                            // if we found a contact with that name offer to update contact info
                            if (returnCollection2.Entities.Count > 0)
                            {
                                firstName = returnCollection2.Entities[0].Attributes["firstname"].ToString();
                                lastName = returnCollection2.Entities[0].Attributes["lastname"].ToString();
                                if (returnCollection2.Entities[0].Attributes.Contains("emailaddress1") == true)
                                    email = returnCollection2.Entities[0].Attributes["emailaddress1"].ToString();
                                companyName = returnCollection2.Entities[0].Attributes["name"].ToString();
                                if (returnCollection2.Entities[0].Attributes.Contains("jobtitle") == true)
                                    jobTitle = returnCollection2.Entities[0].Attributes["jobtitle"].ToString();
                                if (returnCollection2.Entities[0].Attributes.Contains("parentcustomerid") == true)
                                    accountID = ((EntityReference)returnCollection2.Entities[0].Attributes["parentcustomerid"]).Id;

                                contactID = returnCollection2.Entities[0].Attributes["contactid"].ToString();
                                contactGuidId = (Guid)returnCollection2.Entities[0].Attributes["contactid"];
                                MessageForm form = MessageForm.getInstance();
                                form.fadeIn();
                                form.FillData(firstName, lastName, email, companyName, jobTitle, contactGuidId, accountID);
                                callProcessed = true;
                            }
                            // if no contact was found offer to create a new contact
                            else
                            {
                                CreateForm form = CreateForm.getInstance();
                                form.fadeIn();
                                callProcessed = true;
                                
                            }
                        }
                    }

                }
                else
                if (call.Status == TCallStatus.clsInProgress)
                {
                    startTime = DateTime.Now;
                }
                else
                if (call.Status == TCallStatus.clsCancelled || call.Status == TCallStatus.clsMissed)
                {
                    callProcessed = false;
                }
                else
                // If call is finished create a Skype Call activity
                if (call.Status == TCallStatus.clsFinished && callProcessed)
                {
                    callProcessed = false;
                    MessageForm form = MessageForm.getInstance();
                    form.fadeOut();
                    
                    endTime = DateTime.Now;

                    // Create Skype activity in CRM
                    Entity skypeCall = new Entity("new_skypecall");
                    skypeCall["subject"] = "Skype call";
                    skypeCall["regardingobjectid"] = new EntityReference("account", accountID) ;
                    skypeCall["new_contact"] = new EntityReference("contact", contactGuidId);
                    skypeCall["actualdurationminutes"] = (endTime - startTime).Minutes;
                    Guid _skypeCallId = _service.Create(skypeCall);

                    // Create all skype messages and write them to server
                    foreach (Entity skypeMessage in skypeMessages)
                    {
                        skypeMessage["new_skypecallid"] = new EntityReference("new_skypecall", _skypeCallId);
                        _service.Create(skypeMessage);
                    }

                    // Open up created Skype Call activity
                    Uri link = new Uri("http://" + crmServer + ":" + crmServerPort + "/" + crmOrgName + "/main.aspx?etn=new_skypecall&id=%7b" + _skypeCallId.ToString() + "%7d&pagetype=entityrecord");                                                  
                    Process.Start(link.ToString());
                }
            }
            catch (Exception e)
            {
                MessageBox.Show(e.ToString());
            }
        }

        void IncomingCall_MessageStatus(ChatMessage pMessage, TChatMessageStatus Status)
        {
            // Check if we received a call. This solution doesn't still work for IM sessions only.
            if (Status == TChatMessageStatus.cmsSent)
            {
                if (contactID == null)
                {
                    return;
                }

                int type = 0;
                // check what type of message (sent or received)
                switch (Status)
                {
                    case TChatMessageStatus.cmsReceived:
                        type = 0;
                        break;
                    case TChatMessageStatus.cmsSent:
                        type = 1;
                        break;
                }

                // Create a new Skype message referencing Skype Call and add it to the array list
                Entity skypeMessage = new Entity("new_skypemessage");
                skypeMessage["new_message"] = pMessage.Body;
                skypeMessage["new_datetime"] = pMessage.Timestamp.ToUniversalTime();
                skypeMessage["new_type"] = new OptionSetValue(type);
                skypeMessages.Add(skypeMessage);

            }

        }

        public EntityCollection SearchBySkypeUsername(string skypeName)
        {
            // Search for contact using Skype username          
            string fetch2 = @"<fetch distinct='false' mapping='logical' aggregate='false'>
                    <entity name='contact'>
                        <attribute name='contactid'/>
                        <attribute name='firstname'/>
		                <attribute name='lastname'/>
		                <attribute name='emailaddress1'/>
		                <attribute name='parentcustomerid'/>
		                <attribute name='jobtitle'/>
		                <filter type='and'>
                            <condition attribute='new_skypeusername' operator='eq' value='" + skypeName + @"'/>
                        </filter>
                         <link-entity name='account' from='accountid' to='parentcustomerid' link-type='outer'>
                            <attribute name='name' alias='name' />
         	            </link-entity>
                    </entity>
                </fetch>";

         
            // Fetch the results.
            RetrieveMultipleRequest fetchRequest1 = new RetrieveMultipleRequest
            {
                Query = new FetchExpression(fetch2)
            };

          
            EntityCollection e = ((RetrieveMultipleResponse)_service.Execute(fetchRequest1)).EntityCollection;
            
            return e;
        }

        public EntityCollection SearchByContactName(string contactname)
        {
            // Search contacts using Skype display name
            string fetch2 = @"<fetch distinct='false' mapping='logical' aggregate='false'>
                    <entity name='contact'>
                        <attribute name='contactid'/>
                        <attribute name='firstname'/>
		                <attribute name='lastname'/>
		                <attribute name='emailaddress1'/>
		                <attribute name='parentcustomerid'/>
		                <attribute name='jobtitle'/>
		                <filter type='and'>
                            <condition attribute='fullname' operator='eq' value='" + contactname + @"'/>
                        </filter>
                         <link-entity name='account' from='accountid' to='parentcustomerid' link-type='outer'>
                            <attribute name='name' alias='name' />
         	            </link-entity>
                    </entity>
                </fetch>";


            // Fetch the results.
            RetrieveMultipleRequest fetchRequest1 = new RetrieveMultipleRequest
            {
                Query = new FetchExpression(fetch2)
            };


            EntityCollection e = ((RetrieveMultipleResponse)_service.Execute(fetchRequest1)).EntityCollection;

            return e;
        }


        private void notifyTrayForm_DoubleClick(object sender, EventArgs e)
        {
            MessageForm m = MessageForm.getInstance();
            m.fadeIn();
        }

        private void menuProperties_Click(object sender, EventArgs e)
        {
            SkypeConnector.Configuration config = new Configuration();
            config.Show();
        }

        private void menuExit_Click(object sender, EventArgs e)
        {
            this.Close();
            System.Windows.Forms.Application.Exit();
        }


    }
}
